home *** CD-ROM | disk | FTP | other *** search
/ Aminet 3 / Aminet 3 - July 1994.iso / Aminet / util / cli / ATT_awk_1_0.lha / AT&T-awk / Amigasrc.lha / amiga.c next >
Encoding:
C/C++ Source or Header  |  1994-06-04  |  10.8 KB  |  476 lines

  1. /*
  2.  *  This file provides the necessary parts for making
  3.  *  the Amiga version of AT&T awk fly.
  4.  *
  5.  *  Compile with SAS/C 6.51 to get maximum functionality.
  6.  *  Needs V36+ system includes to compile.
  7.  *  Will use arp.library for pattern matching if it is
  8.  *  available when running under pre-V36 AmigaDOS.
  9.  *
  10.  *  This file is Copyright (c) 1994 Torsten Poulin
  11.  *  Freely redistributable.
  12.  *
  13.  *  Torsten Poulin (torsten@diku.dk)
  14.  *  2-Jun-94
  15.  */
  16.  
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <stdlib.h>
  20.  
  21. static const char AMIGAver[] = "\0$VER: AT&T-awk 1.0 (2.6.94)";
  22.  
  23. #ifdef __SASC
  24.  
  25. #include <errno.h>
  26.  
  27. #include <workbench/startup.h>
  28. #include <libraries/dos.h>
  29. #include <libraries/dosextens.h>
  30. #include <exec/memory.h>
  31. #include <dos/var.h>
  32. #include <dos/dostags.h>
  33. #include <dos/dosasl.h>
  34. #include <proto/dos.h>
  35. #include <proto/exec.h>
  36.  
  37. extern char __stdiowin[];
  38. extern char __stdiov37[];
  39. extern long __stack = 64 * 1024; /* This should be more than enough */
  40.  
  41. extern struct WBStartup *_WBenchMsg;
  42. int main(int, void *);
  43.  
  44. static int argc;        /* arg count */
  45. static char **targv, **argv;    /* arg pointers */
  46.  
  47. #ifdef USE_ARP
  48.  
  49. struct ARPAnchorPath {
  50.   void *ARP_private1;
  51.   void *ARP_private2;
  52.   LONG ARP_private3;
  53.   LONG ARP_private4;
  54.   BYTE ARP_ap_Flags;
  55.   BYTE ARP_private5;
  56.   WORD ARP_ap_Strlen;
  57.   struct FileInfoBlock ARP_ap_Info; 
  58.   BYTE ARP_ap_Buf[1];
  59. };
  60.  
  61. #define    ARP_APB_DOWILD 0L
  62. #define    ARP_APF_DOWILD (1L << ARP_APB_DOWILD)
  63.  
  64. #pragma libcall ArpBase ArpFindFirst 1bc 8002
  65. #pragma libcall ArpBase ArpFindNext 1c2 801
  66. #pragma libcall ArpBase ArpFreeAnchorChain 1c8 801
  67.  
  68. LONG ArpFindFirst(char *, struct ARPAnchorPath *);
  69. LONG ArpFindNext(struct ARPAnchorPath *);
  70. VOID ArpFreeAnchorChain(struct ARPAnchorPath *);
  71.  
  72. struct Library *ArpBase;
  73.  
  74. #endif
  75.  
  76. #endif /* __SASC */
  77.  
  78.  
  79.  
  80. /*
  81.  * Pipes are implemented in a simplistic
  82.  * MS-DOS kind of way using temporary files for now.
  83.  * Matt Dillons's FifoLib would be a better solution, though.
  84.  * The official queue.handler (pipe.handler in V33) isn't a
  85.  * good candidate as it doesn't handle broken pipes gracefully.
  86.  *
  87.  * The present versions of popen() og pclose() call system()
  88.  * with "command >TMPFILE" and "command TMPFILE" when the pipe
  89.  * is opened for reading and writing, respectively.
  90.  */
  91.  
  92. #define MAX_CMD_LEN 128
  93.  
  94. struct pipe_info {
  95.   FILE *handle;
  96.   int ret_val;
  97.   char tmp_name[L_tmpnam+1];
  98.   char cmd[MAX_CMD_LEN+1];
  99. };
  100.  
  101. static struct pipe_info pipes[FOPEN_MAX];
  102. static char pipe_cmd[MAX_CMD_LEN+2+L_tmpnam+1];
  103.  
  104. FILE *popen(const char *command, const char *type)
  105. {
  106.   int pipe;
  107.  
  108.   if (strlen(command) > MAX_CMD_LEN) return NULL;
  109.  
  110.   for (pipe = 0; pipe < FOPEN_MAX; pipe++)
  111.     if (!pipes[pipe].handle) break;
  112.   if (pipe == FOPEN_MAX) return NULL; /* no available phandle */
  113.  
  114.   if (*type == 'r') {
  115.     /*
  116.      * pipe opened for reading
  117.      */
  118.     strcpy(pipes[pipe].tmp_name, tmpnam(NULL));
  119.     sprintf(pipe_cmd, "%s >%s", command, pipes[pipe].tmp_name);
  120.     pipes[pipe].ret_val = system(pipe_cmd);
  121.  
  122.     if (!(pipes[pipe].handle = fopen(pipes[pipe].tmp_name, "r"))) {
  123.       /*
  124.        * Something went wrong, clean up.
  125.        */
  126.       memset(&pipes[pipe], 0, sizeof(struct pipe_info));
  127.       remove(pipes[pipe].tmp_name);
  128.     }
  129.   }
  130.   else if (*type == 'w') {
  131.     /*
  132.      * pipe opened for writing
  133.      */
  134.     strcpy(pipes[pipe].tmp_name, tmpnam(NULL));
  135.     if (pipes[pipe].handle = fopen(pipes[pipe].tmp_name, "w"))
  136.       strcpy(pipes[pipe].cmd, command);
  137.   }
  138.  
  139.   return pipes[pipe].handle;
  140. }
  141.  
  142. int pclose(FILE *stream)
  143. {
  144.   int pipe;
  145.   int ret = 127;
  146.  
  147.   for (pipe = 0; pipe < FOPEN_MAX; pipe++)
  148.     if (pipes[pipe].handle == stream) {
  149.  
  150.       if (!*pipes[pipe].cmd) {
  151.     /*
  152.      * No cmd, so it must be a pipe opened for reading.
  153.      */
  154.     if (stream) {
  155.       fclose(stream);
  156.       remove(pipes[pipe].tmp_name);
  157.     }
  158.     ret = pipes[pipe].ret_val;
  159.     memset(&pipes[pipe], 0, sizeof(struct pipe_info));
  160.     break;
  161.       }
  162.       else {
  163.     /*
  164.      * It was a pipe opened for writing, so we have
  165.      * to feed the data to the command.
  166.      */
  167.     sprintf(pipe_cmd, "%s %s", pipes[pipe].cmd, pipes[pipe].tmp_name);
  168.     if (stream) {
  169.       fclose(stream);
  170.       ret = system(pipe_cmd);
  171.       remove(pipes[pipe].tmp_name);
  172.     }
  173.     memset(&pipes[pipe], 0, sizeof(struct pipe_info));
  174.     break;
  175.       }
  176.     }
  177.   return ret;
  178. }
  179.  
  180. #ifdef __SASC
  181. /*
  182.  * Erase any remaining temporary files.
  183.  */
  184. void __stdargs _STD_30000_tmpfilecleanup(void)
  185. {
  186.   int pipe;
  187.  
  188.   for (pipe = 0; pipe < FOPEN_MAX; pipe++) {
  189.     if (pipes[pipe].handle) fclose(pipes[pipe].handle);
  190.     if (*pipes[pipe].tmp_name) remove(pipes[pipe].tmp_name);
  191.   }
  192. }
  193. #endif
  194.  
  195.  
  196. static char *empty_env = NULL;    /* A default empty environment */
  197.  
  198. #ifndef __SASC
  199.  
  200. char **environ = &empty_env;    /* An empty environment variable list */
  201.  
  202. #else /* __SASC */
  203.  
  204. char **environ;            /* Unix style environment variable list */
  205. static long env_size = 0;
  206.  
  207. /*
  208.  * Build a UNIX style environ variable from the AmigaDOS environment.
  209.  * Can only recognize local shell variables.
  210.  *
  211.  * Stolen from David Gay's Amiga port of GNU Emacs :-)
  212.  */
  213.  
  214. static void make_environ(void)
  215. {
  216.   int env_count = 0;
  217.   long env_len = 0;
  218.   struct LocalVar *scan_env;
  219.   char **new_environ, *env_text;
  220.   struct Process *process;
  221.  
  222.   if (DOSBase->dl_lib.lib_Version < 37) {
  223.     environ = &empty_env;    /* no local vars in pre-V37, sorry */
  224.     return;
  225.   }
  226.   
  227.   process = (struct Process *) FindTask(NULL);
  228.  
  229.   for (scan_env = (struct LocalVar *) process->pr_LocalVars.mlh_Head;
  230.        scan_env->lv_Node.ln_Succ;
  231.        scan_env = (struct LocalVar *) scan_env->lv_Node.ln_Succ)
  232.     if (scan_env->lv_Node.ln_Type == LV_VAR &&
  233.     !(scan_env->lv_Flags & (GVF_GLOBAL_ONLY | GVF_BINARY_VAR))) {
  234.       /*
  235.        * We only handle local text variables
  236.        */
  237.       env_count++;
  238.       env_len += 2 + strlen(scan_env->lv_Node.ln_Name) + scan_env->lv_Len;
  239.     }
  240.  
  241.   env_size = sizeof(char *) * (1 + env_count) + env_len;
  242.   new_environ = environ = AllocMem(env_size, MEMF_CLEAR);
  243.  
  244.   env_text = (char *) (environ + (1 + env_count));
  245.   if (!environ) environ = &empty_env;
  246.   else {
  247.     for (scan_env = (struct LocalVar *) process->pr_LocalVars.mlh_Head;
  248.      scan_env->lv_Node.ln_Succ;
  249.      scan_env = (struct LocalVar *) scan_env->lv_Node.ln_Succ)
  250.       if (scan_env->lv_Node.ln_Type == LV_VAR &&
  251.       !(scan_env->lv_Flags & (GVF_GLOBAL_ONLY | GVF_BINARY_VAR))) {
  252.     /*
  253.      * We only handle local text variables
  254.      */
  255.     char *env_name = scan_env->lv_Node.ln_Name;
  256.     int env_len = scan_env->lv_Len;
  257.  
  258.     *new_environ++ = env_text;
  259.     while (*env_name) *env_text++ = *env_name++;
  260.     *env_text++ = '=';
  261.     env_name = scan_env->lv_Value;
  262.     while (env_len--) *env_text++ = *env_name++;
  263.     *env_text++ = '\0';
  264.       }
  265.     *new_environ = 0;
  266.   }
  267. }
  268.  
  269. void __stdargs _STD_250_envcleanup(void)
  270. {
  271.   if (environ != &empty_env) FreeMem(environ, env_size);
  272. }
  273.  
  274.  
  275. #define SQUOTE  '\''
  276. #define DQUOTE  '"'
  277. #define ESCAPE  '*'
  278.  
  279. #define LINE_GROW 128
  280.  
  281. #define isspace(c)      ((c == ' ')||(c == '\t') || (c == '\n'))
  282.  
  283. static char *parambuf;
  284. static int paramlen = LINE_GROW, idx = 0;
  285.  
  286. static void copychar(char c)
  287. {
  288.   if (idx < paramlen) parambuf[idx++] = c;
  289.   else {
  290.     paramlen += LINE_GROW;
  291.     if (!(parambuf = realloc(parambuf, paramlen))) exit(20);
  292.     parambuf[idx++] = c;
  293.   }
  294. }
  295.  
  296.  
  297. #define NAMELEN 255
  298.  
  299. static char pattern[NAMELEN+1];
  300. static struct AnchorPath *ap;
  301.  
  302. static char *patternmatch(char *line)
  303. {
  304.   int ispattern = 0;
  305.   char *c;
  306.  
  307.   for (c = pattern; *line && !isspace(*line); ++line)
  308.     if (c - pattern < NAMELEN) {
  309.       if (*line == '~' || *line == '#' || *line == '?' || *line == '*' ||
  310.       *line == '%' || *line == '(' || *line == '[' || *line == '|')
  311.     ispattern = 1;
  312.       *c++ = *line;
  313.     }
  314.   *c = '\0';
  315.  
  316. #ifndef USE_ARP
  317.   if (DOSBase->dl_lib.lib_Version < 36) ispattern = 0;
  318. #else
  319.   if (ispattern && DOSBase->dl_lib.lib_Version < 36) {
  320.     struct ARPAnchorPath *ArpAP;
  321.  
  322.     if (!(ArpAP = malloc(sizeof(struct ARPAnchorPath)+NAMELEN+1)))
  323.       exit(20);
  324.     memset(ArpAP, 0, sizeof(struct ARPAnchorPath) + NAMELEN + 1);
  325.  
  326.     ArpAP->ARP_ap_Strlen = NAMELEN;
  327.     ArpAP->ARP_ap_Flags = ARP_APF_DOWILD;
  328.  
  329.     if (ArpBase = OpenLibrary("arp.library", 39L)) {
  330.       if ((ArpFindFirst(pattern, ArpAP)) == 0)
  331.     do
  332.     {
  333.       if (ArpAP->ARP_ap_Info.fib_DirEntryType < 0 ) {
  334.         ++argc;
  335.         for (c = ArpAP->ARP_ap_Buf; *c; ++c) copychar(*c);
  336.         copychar('\0');
  337.       }
  338.     } while ((ArpFindNext(ArpAP)) == 0);
  339.       ArpFreeAnchorChain(ArpAP);
  340.       CloseLibrary(ArpBase);    /* no reason to let it stay open */
  341.     }
  342.     else ispattern = 0;        /* No arp.library => no patterns */
  343.     free(ArpAP);
  344.   }
  345. #endif
  346.  
  347.   if (ispattern) {
  348.     if ((MatchFirst(pattern, ap)) == 0)
  349.       do
  350.       {
  351.     if (ap->ap_Info.fib_DirEntryType < 0) {
  352.       ++argc;
  353.       for (c = ap->ap_Buf; *c; ++c) copychar(*c);
  354.       copychar('\0');
  355.     }
  356.       } while ((MatchNext(ap)) == 0);
  357.     MatchEnd(ap);
  358.   }
  359.  
  360.   if (!ispattern) {
  361.     ++argc;
  362.     for (c = pattern; *c; ++c) copychar(*c);
  363.     copychar('\0');
  364.   }
  365.  
  366.   return line;
  367. }
  368.  
  369.  
  370. void __stdargs __main(char *line)
  371. {
  372.   int ret, i;
  373.  
  374.   if (!(parambuf = malloc(paramlen))) exit(20);
  375.   if (!(ap = malloc(sizeof(struct AnchorPath) + NAMELEN + 1))) exit(20);
  376.   memset(ap, 0, sizeof(struct AnchorPath) + NAMELEN + 1);
  377.   ap->ap_Strlen = NAMELEN;
  378.  
  379.   for (argc = 0;;) {
  380.     while (isspace(*line)) ++line;
  381.     if (!*line) break;
  382.     if (*line == SQUOTE) {
  383.       ++line;
  384.       ++argc;
  385.       while (*line != SQUOTE && *line) {
  386.     if (*line == ESCAPE) {
  387.       line++;
  388.       if (!*line) {
  389.         copychar('\0');
  390.         goto linedone;
  391.       }
  392.     }
  393.         copychar(*line++);
  394.       }
  395.       if (*line) ++line;
  396.       copychar('\0');
  397.     }
  398.     else if (*line == DQUOTE) {
  399.       ++line;
  400.       ++argc;
  401.       while (*line != DQUOTE && *line) {
  402.     if (*line == ESCAPE) {
  403.       line++;
  404.       if (!*line) {
  405.         copychar('\0');
  406.         goto linedone;
  407.       }
  408.     }
  409.         copychar(*line++);
  410.       }
  411.       if (*line) ++line;
  412.       copychar('\0');
  413.     }
  414.     else {            /* non-quoted arg */
  415.       line = patternmatch(line);
  416.       if (!*line) break;
  417.     }
  418.   }                /* while */
  419.  linedone:
  420.  
  421.   free(ap);
  422.  
  423.   if (argc) {
  424.     if (!(argv = malloc((argc + 1) * sizeof(char *)))) exit(20);
  425.     memset(argv, 0, (argc + 1) * sizeof(char *));
  426.     
  427.     argv[0] = parambuf;
  428.     for (i = 1; i < argc; )
  429.       if (!*parambuf++)    argv[i++] = parambuf;
  430.   }
  431.  
  432.   targv = (argc == 0) ? (char **) _WBenchMsg : (char **) argv;
  433.  
  434.   make_environ();
  435.  
  436.   /*
  437.    * Call user's main program
  438.    */
  439.  
  440.   ret = main(argc, targv);    /* call main function */
  441.  
  442.   exit(ret);
  443. }
  444.  
  445.  
  446.  
  447. /*  Replacement for the SAS/C 6.51 system() function.
  448.  *  This version uses the UserShell which by default
  449.  *  is the same as the boot shell but can be changed
  450.  *  by the user; e.g., to WShell.
  451.  *
  452.  *  Does nothing if passed a NULL pointer or an empty string.
  453.  */
  454.  
  455. int system(const char *s)
  456. {
  457.   int result;
  458.   struct TagItem tags[2];
  459.  
  460.   if (!s || !*s) return 0;
  461.  
  462.   if (DOSBase->dl_lib.lib_Version < 36L) {
  463.     Execute((char *) s, NULL, NULL);
  464.     result = 0; /* nothing reasonable is available... */
  465.   }
  466.   else {
  467.     tags[0].ti_Tag = SYS_UserShell; tags[0].ti_Data = TRUE;
  468.     tags[1].ti_Tag = TAG_END; tags[1].ti_Data = NULL;
  469.     if ((result = (int) System((char *) s, tags)) == -1)
  470.       errno = EOSERR;
  471.   }
  472.   return result;
  473. }
  474.  
  475. #endif /* __SASC */
  476.